<?php
use Swoole\Coroutine\Channel;


class pool
{
    /**
     * 最大避免超标
     * @var [type]
     */
    protected $maxConnection = 30;
    /**
     * 最小连接个数，就是在初始化的时候事先创建多少个
     *
     * 创建太多也会消耗内存，也不一定用的了那么多
     * @var [type]
     */
    protected $minConnection = 5;
    /**
     * 会在协程中使用，保存创建的连接个数
     * @var
     */
    protected $channel;
    // 从连接池中获取连接的时候超时的时间
    protected $timeout = 3;

    protected $count = 0;
    // 允许空闲时间
    protected $idleTime = 10;

    protected static $instance = null;

    private function __construct()
    {
        // var_dump(1);
        $this->init();
        $this->gc();

    }
    /**
     * [getInstance description]
     * 
     * @return pool
     */
    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new static;
        }
        return self::$instance;
    }
    /**
     * 初始化
     *
     * 创建连接，并且把连接放在连接池中
     * 
     * @return [type] [description]
     */
    protected function init()
    {
        $this->channel = new Channel($this->maxConnection);
        for ($i=0; $i < $this->minConnection; $i++) {
            $connection = $this->createConnection();
            if ($connection) {
                $this->channel->push($connection);
                $this->count++;
            }
        }
    }

    public function call($conn, $method, $sql)
    {
        try {
            return $conn['db']->{$method}($sql);
        } catch (\Exception $e) {

        }
    }
    // 创建连接
    protected function createConnection()
    {
        try {
            $pdo = new PDO('mysql:host=localhost;dbname=swoole', 'root', '0000');
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return [
              'last_used_time' => time(),
               'db' =>$pdo
            ];
        } catch (\Exception $e) {
            return false;
        }
    }
    /**
     * 获取连接并使用
     *
     *
     * 
     * @return PDO
     */
    public function getConnection()
    {
        $connection = null;
        if ($this->channel->isEmpty()) {
            // 表示没有连接可用
            // 没有连接就要创建
            if ($this->count < $this->maxConnection) {
                // 判断是否超过最大连接个数
                $this->createConnection();
                if ($connection) {
                    $this->channel->push($connection);
                    $this->count++;
                }
            } else {
                var_dump("等待获取连接");
                // $connection = $this->channel->pop($this->timeout);
            }
        }
        // 表示还有空余的连接
        return $this->channel->pop($this->timeout);

        // $connection;
        // var_dump("超时");
    }

    /**
     * 释放连接（重回连接池）
     * 
     * @param  [type] $connection [description]
     * @return [type]             [description]
     */
    public function freeConnection($connection)
    {
        $connection['last_used_time'] = time();
        $this->channel->push($connection);
    }
    /**
     * 回收空闲的连接
     * 
     */
    protected function gc()
    {
        // 定时检测连接
        swoole_timer_tick(2000, function(){
            $conns = [];// 记录可用的连接
            // 要检测的连接不止一个
            while (true) {
                if (!$this->channel->isEmpty() && $this->count > $this->minConnection) {
                    $connection = $this->channel->pop();
                    var_dump($connection);
                    if (empty($connection)) {
                        continue;
                    }
                    // 检测是否空闲
                    if ((time()- $connection['last_used_time']) > $this->idleTime) {
                        $this->count--;
                        $connection['db'] = null;
                        echo "回收成功\n";
                    } else {
                        // 没有超过空闲时间就放回去
                        array_push($conns, $connection);
                    }
                } else {
                    break;
                }
            }
            foreach ($conns as $key => $value) {
                $this->channel->push($value);
            }
              var_dump($this->channel->length());
            echo "当前连接数是多少：".$this->count;
        });
    }
}
